<!DOCTYPE html>
<html lang="zh">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>grid 布局</title>
    <style type="text/css"></style>
  </head>

  <body>
    <div id="button">这里要用来点击的</div>
  </body>

  <script>
    // 简单的发布订阅者模式
    {
      var Event = (function () {
        var clientList = {},
          listen,
          trigger,
          remove;
        listen = function (key, fn) {
          if (!clientList[key]) {
            clientList[key] = [];
          }
          clientList[key].push(fn);
        };

        trigger = function () {
          var key = Array.prototype.shift.call(arguments),
            fns = clientList[key];
          if (!fns || fns.length === 0) {
            return false;
          }
          for (var i = 0, fn; (fn = fns[i++]); ) {
            fn.apply(this, arguments);
          }
        };

        remove = function (key, fn) {
          var fns = clientList[key];
          if (!fns) {
            return false;
          }
          if (!fn) {
            fns && (fns.length = 0);
          } else {
            for (var l = fns.length - 1; l >= 0; l--) {
              var _fn = fns[l];
              if (_fn === fn) {
                fns.splice(l, 1);
              }
            }
          }
        };

        return {
          listen,
          trigger,
          remove,
        };
      })();

      Event.listen("squeee", (price) => {
        console.log("价格" + price);
      });

      Event.trigger("squeee", 200000);

      Event.listen("squeee", (price) => {
        console.log("思路" + price);
      });
    }

    // 带缓存的可先发布再订阅的发布订阅者模式
    {
      var Event = (function () {
        var global = this,
          Event,
          _default = "default";

        Event = (function () {
          var _listen,
            _trigger,
            _remove,
            _slice = Array.prototype.slice,
            _shift = Array.prototype.shift,
            _unshift = Array.prototype.unshift,
            namespaceCache = {},
            _create,
            find,
            each = function (ary, fn) {
              var ret;
              for (var i = 0, l = ary.length; i < l; i++) {
                var n = ary[i];
                ret = fn.call(n, i, n);
              }
              return ret;
            };

          _listen = function (key, fn, cache) {
            if (!cache[key]) {
              cache[key] = [];
            }
            cache[key].push(fn);
          };

          _remove = function (key, cache, fn) {
            if (cache[key]) {
              if (fn) {
                for (var i = cache[key].length; i >= 0; i--) {
                  if (cache[key][i] === fn) {
                    cache[key].splice(i, 1);
                  }
                }
              } else {
                cache[key] = [];
              }
            }
          };

          _trigger = function () {
            var cache = shift.call(arguments),
              key = _shift.call(arguments),
              args = arguments,
              _self = this,
              ret,
              stack = cache[key];

            if (!stack || !stack.length) {
              return;
            }

            return each(stack, function () {
              return this.apply(_self, args);
            });
          };

          _create = function (namespace) {
            var namespace = namespace || _default;
            var cache = {},
              offlineStack = [], //离线事件
              ret = {
                listen: function (key, fn, last) {
                  _listen(key, fn, cache);
                  if (offlineStack === null) {
                    return;
                  }
                  if (last === "last") {
                    offlineStack.length && offlineStack.pop();
                  } else {
                    each(offlineStack, function () {
                      this();
                    });
                  }
                  offlineStack = null;
                },

                one: function (key, fn, last) {
                  _remove(key, cache);
                  this.listen(key, fn, last);
                },

                remove: function (key, cn) {
                  _remove(key, cache, fn);
                },

                trigger: function () {
                  var fn,
                    args,
                    _self = this;
                  _unshift.call(arguments, cache);
                  args = arguments;
                  fn = function () {
                    return _trigger.apply(_self, args);
                  };
                  if (offlineStack) {
                    return offlineStack.push(fn);
                  }
                  return fn();
                },
              };
            return namespace
              ? namespaceCache[namespace]
                ? namespaceCache[namespace]
                : (namespaceCache[namespace] = ret)
              : ret;
          };
          return {
            create: _create,

            one: function (key, fn, last) {
              var event = this.create();
              event.one(key, fn, last);
            },

            remove: function (key, fn) {
              var event = this.create();
              event.remove(key, fn);
            },

            listen: function (key, fn, last) {
              var event = this.create();
              event.listen(key, fn, last);
            },

            trigger: function () {
              var event = this.create();
              event.trigger.apply(this, arguments);
            },
          };
        })();

        return Event;
      })();
    }
  </script>
</html>
